unit UnitStackTrace;

interface

uses System.SysUtils;

type
  TLog_StackTrace = class
    private
      procedure HandleAppException(Sender: TObject; E: Exception);
  end;

implementation

uses Winapi.Windows, System.Variants, System.Classes, Vcl.Clipbrd, System.UITypes,
     Vcl.Forms, Vcl.Dialogs, JclDebug;

var Log_StackTrace: TLog_StackTrace;

procedure TLog_StackTrace.HandleAppException(Sender: TObject; E: Exception);
var StackTrace: TStringList;
    ModuleName: string;
begin
  ModuleName := ExtractFilename(ParamStr(0));
  StackTrace := TStringList.Create;
  try
    StackTrace.Add(Format('{%s} %s %s %s', [ModuleName, '*************************************',
                                            E.Message,  '*************************************']));
    JclLastExceptStackListToStrings(StackTrace, True, True, True, True);
    OutputDebugString(PChar(StackTrace.Text));
    if (MessageDlg(Format('Exception: %s occurred.%s%s', [E.Message, #10#10, 'Copy stacktrace to ClipBoard?']), mtError, [mbYes, mbNo], 0) = ID_Yes) then
      Clipboard.AsText := StackTrace.Text;
  finally
    StackTrace.Free;
  end;
end;

initialization
  // Enable raw mode (default mode uses stack frames which aren't always generated by the compiler)
  Include(JclStackTrackingOptions, stRawMode);
  // Disable stack tracking in dynamically loaded modules (it makes stack tracking code a bit faster)
  Include(JclStackTrackingOptions, stStaticModuleList);
  // Initialize Exception tracking
  JclStartExceptionTracking;

  Log_StackTrace := TLog_StackTrace.Create;
  Application.OnException := Log_StackTrace.HandleAppException;

finalization
  JclStopExceptionTracking;
  Log_StackTrace.Free;

end.
